﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenTK;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Input;
using System.Drawing;
using OpenTK.Graphics;
using Common;

namespace T12_Extensions {
    class T12_ExtensionsGameWindow : GameWindow {
        public T12_ExtensionsGameWindow() {
            this.Load += T12_ExtensionsGameWindow_Load;
            this.Resize += T12_ExtensionsGameWindow_Resize;
            this.RenderFrame += T12_ExtensionsGameWindow_RenderFrame;
            this.Unload += T12_ExtensionsGameWindow_Unload;
            this.Width = 1280;
            this.Height = 720;
            this.Title = "T12_ExtensionsGameWindow";
        }

        private void DebugGL(DebugSource source, DebugType type, int id, DebugSeverity severity, int length, IntPtr message, IntPtr userParam) {
            Console.Write("OpenGL Debug Output Message : ");
            Console.Write(TranslageSource(source));
            Console.Write(TranslageType(type));
            Console.Write(TranslageSeverity(severity));
            Console.WriteLine($"Message :{message}");


        }

        private string TranslageSeverity(DebugSeverity severity) {
            switch (severity) {
                case DebugSeverity.DebugSeverityHigh:
                    return "Severity : HIGH; ";
                case DebugSeverity.DebugSeverityMedium:
                    return "Severity : MEDIUM; ";
                case DebugSeverity.DebugSeverityLow:
                    return "Severity : LOW; ";
                default:
                    return "";
            }
        }

        private string TranslageType(DebugType type) {
            switch (type) {
                case DebugType.DebugTypeError:
                    return "Type : ERROR; ";
                case DebugType.DebugTypeDeprecatedBehavior:
                    return "Type : DEPRECATED_BEHAVIOR; ";
                case DebugType.DebugTypeUndefinedBehavior:
                    return "Type : UNDEFINED_BEHAVIOR; ";
                case DebugType.DebugTypePortability:
                    return "Type : PORTABILITY; ";
                case DebugType.DebugTypePerformance:
                    return "Type : PERFORMANCE; ";
                case DebugType.DebugTypeOther:
                    return "Type : OTHER; ";
                default:
                    return "";
            }
        }

        private string TranslageSource(DebugSource source) {
            switch (source) {
                case DebugSource.DebugSourceApi:
                    return "Source : API; ";
                case DebugSource.DebugSourceWindowSystem:
                    return "Source : WINDOW_SYSTEM; ";
                case DebugSource.DebugSourceShaderCompiler:
                    return "Source : SHADER_COMPILER; ";
                case DebugSource.DebugSourceThirdParty:
                    return "Source : THIRD_PARTY; ";
                case DebugSource.DebugSourceApplication:
                    return "Source : APPLICATION; ";
                default:
                    return "Source : OTHER; ";
            }
        }

        private void T12_ExtensionsGameWindow_RenderFrame(object sender, FrameEventArgs e) {
            GL.ClearColor(.1f, .1f, .99f, .9f);
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

            Render();

            SwapBuffers();
            ProcessEvents();
        }

        Shader shader;
        Vao vao;
        Texture2D texture;
        ModelMesh mesh;
        Vbo<Vector3> vertexBuffer, normalBuffer;
        Vbo<Vector2> uvBuffer;
        Vbo<ushort> indexBuffer;
        VertexAttribManager attribs = new VertexAttribManager();
        private void T12_ExtensionsGameWindow_Load(object sender, EventArgs e) {
                       
            VSync = VSyncMode.Off;
            GL.DebugMessageCallback(new DebugProc(DebugGL), IntPtr.Zero);
            GL.Enable(EnableCap.DebugOutputSynchronous);

            GL.Enable((EnableCap)All.Depth);
            GL.DepthFunc((DepthFunction)All.Left);
            GL.Enable((EnableCap)All.CullFaceMode);

            shader = new Shader("shader.vs", "shader.fs");
            vao = new Vao();
            texture = Texture2D.Load("uvmap.dds");
            mesh = MeshLoader.LoadObjIndexed("suzanne.obj");
            vertexBuffer = new Vbo<Vector3>(mesh.Vertices);
            uvBuffer = new Vbo<Vector2>(mesh.Uvs);
            normalBuffer = new Vbo<Vector3>(mesh.Normals);
            indexBuffer = new Vbo<ushort>(BufferTarget.ElementArrayBuffer, BufferUsageHint.StaticDraw, mesh.Indices);

            attribs.AddAttrib(3, vertexBuffer);
            attribs.AddAttrib(2, uvBuffer);
            attribs.AddAttrib(3, normalBuffer);

        }

        private void Render() {
            shader.Use();
            InputControls.computeMatricesFromInput(this);
            FpsCounter.CountFps();
            var model = Matrix4.Identity;
            var mvp = model * InputControls.ViewMatrix * InputControls.ProjectionMatrix;
            shader.SetMatrix4("M", ref model);
            shader.SetMatrix4("V", ref InputControls.ViewMatrix);
            shader.SetMatrix4("MVP", ref mvp);

            Vector3 lightPos = new Vector3(4, 4, 4);
            shader.SetVector3("LightPosition_worldspace", lightPos);
            texture.Active(TextureUnit.Texture1, shader, "myTextureSampler");
            attribs.Enable();
            GL.DrawElements(BeginMode.Triangles, mesh.Indices.Length, DrawElementsType.UnsignedShort, 0);
            attribs.Disable();
        }

        private void T12_ExtensionsGameWindow_Resize(object sender, EventArgs e) {
            GL.Viewport(0, 0, Width, Height);
        }



        private void T12_ExtensionsGameWindow_Unload(object sender, EventArgs e) {
            //shader.Dispose();
            GlDisposableObjectBase.DisposeAllDisposableMembers(this);
        }

    }
}
